Operasi Image Filtering dan Thresholding

Minggu ini, kita akan membahas mengenai bagaimana sebuah citra bukan hanya dapat dianggap tersusun dari matriks, melainkan juga sebagai sebuah fungsi matematis yang dapat diolah dengan menggunakan berbagai operasi matematis. Notebook ini berisi pembahasan mengenai 1) Filtering/Convolution, 2) Thresholding.

Tulis ulang kode program dan jawablah setiap pertanyaan yang diberikan

Image Filtering

Konsep Filtering

Image Filtering (atau convolution) merupakan salah satu teknik pengolahan citra yang banyak digunakan. Filtering menggunakan prinsip pengolahan citra sederhana dimana setiap band pada sebuah citra dianggap sebagai sebuah matriks. Selanjutnya, operasi matematika dilakukan pada matriks tersebut untuk memperoleh atau menguatkan fitur tertentu yang ada pada citra tersebut. Operasi Image Filtering sering digunakan sebagai langkah awal dalam pengolahan (pre-processing) citra, misalnya untuk menghilangkan noise atau memperkuat fitur dengan ciri tertentu pada citra.

Image Filtering bekerja dengan cara menjalankan sebuah 'kernel' (ingat biji jagung: berukuran kecil) atau matriks persegi dengan ukuran tertentu pada seluruh citra secara bertahap. Inilah mengapa operasi kernel pada seringkali disebut sebagai 'moving window'. Link berikut memberikan penjelasan yang sangat baik mengenai bagaimana sebuah filter bekerja.

Dengan perkembangan pada bidang Deep Learning, Convolution menjadi salah satu teknik penting yang digunakan untuk mengekstraksi fitur level rendah dari sebuah gambar. Karenanya, memahami konsep ini diperlukan untuk memahami bagaimana cara Deep Learning bekerja, khususnya pada metode seperti Convolution Neural Network (CNN). Lihat link berikut untuk memberikan gambaran bagaimana algoritma CNN menggunakan convolution untuk mengenali sebuah objek.

Jika istilah filter terasa familiar , mungkin hal ini karena banyak sosial media (seperti instagram) yang menggunakan prinsip yang sama untuk mengolah foto dari penggunanya.

Melakukan Operasi Image Filtering dengan OpenCV

1. Low-Pass Filtering

OpenCV memiliki berbagai operasi yang dapat digunakan untuk proses filtering, diantaranya: Averaging, Gaussian, Median filter dan Billateral filtering. Pada bagian ini akan dilakukan beberapa percobaan menggunakan fungsi-fungsi OpenCV untuk melakukan Image Filtering. Gunakan data yang diberikan sebagai latihan, atau gunakan gambar yang dapat kalian temukan dari internet.

Sebagai latihan pertama, akan dilakukan filtering pada gambar cat.jpg dengan menggunakan kernel berupa matriks berukuran [5x5] sebagai berikut:

K = $\frac {1}{25} \begin{bmatrix} 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \end{bmatrix}$

In [ ]:
# memanggil modul yang diperlukan
import cv2
import numpy as np
from matplotlib import pyplot as plt
#jika menggunakan google colab jgn lupa load code di bawah ini
#from google.colab.patches import cv2_imshow


#bgr
img = cv2.imread('cat.jpg')

#rgb
cat = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# tampilkan gambar awal tanpa filter
cv2_imshow(img)


# membuat filter: matriks berukuran 5 x 5 
kernel = np.ones((5,5),np.float32)/25
print(kernel)

# lakukan filtering
kucing_filter = cv2.filter2D(img,-1,kernel)

cv2_imshow(kucing_filter)

# salt and pepper
[[0.04 0.04 0.04]
 [0.04 0.04 0.04]
 [0.04 0.04 0.04]]

Selain menggunakan imshow seperti di atas, kita juga dapat menggunakan modul Matplotlib, seperti berikut:

In [ ]:
# perbesar ukuran hasil plotting jika diperlukan
plt.rcParams["figure.figsize"] = (15,15)

# plot pertama, gambar asli
plt.subplot(121),plt.imshow(cat),plt.title('Original')
plt.xticks([]), plt.yticks([])

# kedua, hasil filter
plt.subplot(122),plt.imshow(kucing_filter),
plt.title('Averaging')
plt.xticks([]), plt.yticks([])

# Plot!
plt.show()

Pertanyaan 1: Mengapa hasil plotting berubah warnanya? apa yang perlu dilakukan untuk mengkoreksinya?

Pada script di atas, kernel dibuat dengan menggunakan fungsi numpy (np.ones) dan moving window diterapkan dengan fungsi opencv (filter2D). Kedua fungsi tersebut dapat diganti dengan menggunakan perintah cv2.blur.

In [ ]:
kucing_blur = cv2.blur(img,(5,5))

cv2_imshow(kucing_blur)

Sekarang, bagaimana jika kita ubah kernelnya menjadi seperti berikut

In [ ]:
# ini adalah cara lain untuk membuat sebuah kernel, 
# yaitu dengan menggunakan np.matrix
# kali ini, ukuran matriksnya 3 x 3
kernel = np.matrix([
          [1, 1, 1],
          [1, 2, 1],
          [1, 1, 1]         
          ])/25
print(kernel)

# buat lagi filteringnya
kucing_filter = cv2.filter2D(img,-1,kernel)

# tampilkan
cv2_imshow(kucing_filter)
[[0.04 0.04 0.04]
 [0.04 0.08 0.04]
 [0.04 0.04 0.04]]

Pertanyaan 2: Contoh di atas merupakan Averaging Filter. Seperti namanya, kernel pada filter tersebut dibuat agar seluruh piksel yang bertetangga dikurangi nilainya. Kira-kira apa kegunaan dari filter seperti ini? apa pengaruh ukuran filter pada hasil filtering tersebut?

Fungsi low-pass filter di atas menerapkan rerata pada nilai piksel yang dilewati oleh kernel, sehingga disebut dengan ’moving average’ atau ’averaging’. Terdapat beberapa jenis algoritma low-pass filtering lainnya yang dapat digunakan pada kasus yang berbeda, a.l.:

  1. Gaussian Filter: blur = cv2.GaussianBlur(img,(5,5),0)

  2. Median filtering: median = cv2.medianBlur(img,5)

  3. Billateral Filter: blur = cv2.bilateralFilter(img,9,75,75)

2. High-Pass Filtering

Pada contoh Averaging di atas kita menggunakan kernel dalam bentuk matriks. Sejauh ini kita melakukan operasi citra dengan menganggap tiap band citra merupakan domain matriks yang terdiri dari baris dan kolom. Sejatinya, kita juga dapat merepresentasikan sebuah citra sebagai fungsi matematika yang tersusun dari beberapa parameter. Misalnya seperti berikut:

Dengan demikian, kita juga dapat menerapkan fungsi matematis tertentu pada domain citra tersebut sehingga kita dapat memperoleh citra baru hasil pengolahan. Filtering adalah salah satu operasi yang banyak dilakukan dengan metode ini.

Pada bagian berikut akan diberikan contoh operasi High-pass filtering yang sering digunakan untuk mempertegas tepian sebuah objek pada citra menggunakan operator Sobel dan Laplacian. Berikut adalah contoh operator Sobel:

In [ ]:
# Highpass Filter

# sebenarnya kita tidak perlu melakukan filtering lagi. Cukup sekali saja 
# di bagian awal, selama notebook ini tetap terhubung
import cv2
import numpy as np
from matplotlib import pyplot as plt


# memanggil citra sebagai grayscale (argument 0)
img = cv2.imread('sudoku.jpg',0)

# menerapkan algoritma high-pass filtering:
# laplacian
laplacian = cv2.Laplacian(img,cv2.CV_64F)

# sobel dengan ukuran kernel 5
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=5)

# Catatan:
# CV_64F pada contoh di atas menunjukkan nilai bit dari citra 
# yang dihasilkan serta tipe datanya (F = Float)

# perbesar ukuran hasil plotting 
plt.rcParams["figure.figsize"] = (20,20)


# menampilkan hasil filter
plt.subplot(2,2,1),plt.imshow(img,cmap = 'gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,2),plt.imshow(laplacian,cmap = 'gray')
plt.title('Laplacian'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,3),plt.imshow(sobelx,cmap = 'gray')
plt.title('Sobel X'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,4),plt.imshow(sobely,cmap = 'gray')
plt.title('Sobel Y'), plt.xticks([]), plt.yticks([])
plt.show()

Fungsi di atas menerapkan algoritma dasar high-pass filtering dengan ukuran kernel berupa matriks 5x5. Hasil yang diperoleh merupakan penguatan dari informasi tepi (edge) yang ada pada citra.

OpenCV juga menyediakan algoritma yang khusus digunakan dalam ekstraksi tepi. Diantaranya adalah Canny Edges. Sebagai praktik, gunakan script berikut:

In [ ]:
# memanggil citra sebagai grayscale (argument 0)
img = cv2.imread('baymax.jpg',0)

# memanggil fungsi Canny Edges dengan argument (citra, nilai_min, nilai_max)
edges = cv2.Canny(img,100,200)

plt.subplot(121),plt.imshow(img,cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(edges,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])

plt.show()

Dengan merubah nilai parameter minimum dan maksimum pada perintah cv2.Canny, akan diperoleh lebih banyak atau lebih sedikit detil tergantung pada parameter yang digunakan.

Cobalah gunakan contoh gambar yang lain, kemudian lakukan operasi-operasi di atas dengan merubah parameter yang diberikan untuk melihat bagaimana pengaruhnya.

Image Thresholding

Konsep Thresholding

Thresholding merupakan metode yang digunakan untuk melakukan ekstraksi objek dengan memanipulasi nilai digital number yang melewati batas ambang (‘threshold’) tertentu. Sebuah fungsi kemudian menentukan apa yang terjadi pada nilai piksel yang melewati batas ambang tersebut.

Sebagaimana Filtering, Thresholding juga sering digunakan sebagai perantara pada berbagai pengolahan citra untuk mendapatkan objek yang digambarkan pada citra tersebut. Thresholding merupakan salah satu metode segmentation yang paling sering digunakan.

Menggunakan OpenCV untuk Thresholding

OpenCV memiliki beberapa fungsi untuk Thresholding. Binary Thresholding barangkali adalah yang paling sederhana dan banyak digunakan untuk memisahkan antara objek dengan gambar latar. Berikut adalah contoh bagaimana melakukan thresholding dengan OpenCV

In [ ]:
# membaca gambar baymax 
img = cv2.imread('baymax.jpg',0)

# Hitungan threshold. 
# Perhatikan nilai ambang batas bawah dan atas dari tiap fungsi 
# yang diberikan
ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
ret,thresh2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
ret,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
ret,thresh4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
ret,thresh5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)

# menampilkan hasil
titles = ['Gambar asli','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]

# menampilkan beberapa gambar sekaligus
for i in range(6):
    # 3 baris, 2 kolom
    plt.subplot(3,2,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()

Algoritma di atas merupakan metode Global threshold. Terdapat juga metode lain seperti Adaptive Threshold:

In [ ]:
# masih menggunakan variabel img yang sama
#img = cv2.imread('images/baymax.jpg',0)

# digunakan median blur untuk menghaluskan tepi objek pada citra
# ini diperlukan agar thresholding memberikan hasil lebih baik
img = cv2.medianBlur(img,5)

# Lakukan Thresholding
# Binary Threshold
ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)

# Adaptive Threshold dengan Mean
th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
            cv2.THRESH_BINARY,11,2)

# Adaptive Threshold dengan Gaussian
th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
            cv2.THRESH_BINARY,11,2)


# Plotting
titles = ['Original Image', 'Global Thresholding (v = 127)',
            'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]

# menampilkan hasil
for i in range(4):
    plt.subplot(2,2,i+1)
    plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])
plt.show()

Tugas praktek : No 1. Coba lakukan perubahan pada masing-masing nilai parameter, kemudian lihat hasilnya. Coba juga pada berbagai gambar yang berbeda. Bagaimana hasilnya?

No 2. Cobalah untuk menggunakan data citra lain dan lakukan low pass filtering, high pass filtering dan image thersholding. Serta tampilkan histogram masing-masing citra yang sudah dilakukan filtering